Skip to content

Make decayEffect a continuous function of sample timestamp#33

Open
ps2 wants to merge 1 commit into
tidepool-org:mainfrom
ps2:ps2/decay-effect-continuity
Open

Make decayEffect a continuous function of sample timestamp#33
ps2 wants to merge 1 commit into
tidepool-org:mainfrom
ps2:ps2/decay-effect-continuity

Conversation

@ps2
Copy link
Copy Markdown
Collaborator

@ps2 ps2 commented May 19, 2026

GlucoseValue.decayEffect currently accumulates the decay step-by-step starting from startDate.dateFlooredToTimeInterval(delta). That makes the effect value at any future absolute timestamp depend on which delta-sized simulation bucket the sample's startDate happens to fall into — so two CGM samples a fraction of a minute apart can produce noticeably different effect curves at the same future point, even though the math is supposed to be smooth.

This PR reformulates decayEffect as a closed-form quadratic f(t) = a*t² + b*t + c with t measured from the actual sample timestamp. For samples aligned to delta boundaries the two formulations are mathematically equivalent; for unaligned samples the new formulation removes the bucket-boundary discontinuity.

This is a port of LoopKit/LoopKit#556 by Moti Nisenson-Ken, brought over to the LoopAlgorithm package where decayEffect now lives.

Changes

  • Sources/LoopAlgorithm/LoopMath.swift: reformulated decay computation.
  • Tests/LoopAlgorithmTests/LoopMathTests.swift: new testDecayEffectIsContinuousAcrossSimulationBoundary exercising the continuity property.
  • A handful of existing fixture-calibrated tests had expected values that were tied to the old accumulation; those were re-pinned to the new outputs. Per-prediction drift is on the order of 0.1 mg/dL, which is in line with the original PR author's note that downstream fixtures would need follow-up.

Reformulates decayEffect using a closed-form quadratic in time-since-sample
rather than accumulating step-by-step from the floored simulation boundary.
This makes the effect value at any future absolute timestamp independent of
which delta-sized simulation bucket the sample's startDate falls into.

For samples aligned to delta boundaries the two formulations are
mathematically identical. For unaligned samples (the common case with real
CGM streams) the new formulation removes a small discontinuity that the
old code exhibited at bucket boundaries.

Adds LoopMathTests covering continuity across a delta boundary. Existing
fixture-calibrated tests are re-pinned to the new values; per-prediction
drift is on the order of 0.1 mg/dL.

Ports the LoopMath change from LoopKit/LoopKit#556 by Moti Nisenson-Ken to
the LoopAlgorithm package, where decayEffect now lives.
@ps2 ps2 requested review from Camji55 and nhamming May 19, 2026 17:30
Copy link
Copy Markdown

@nhamming nhamming left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants